package top.codedance.iotp.client.plugins.sync.db.generic;

import top.codedance.iotp.client.ClientApplication;
import top.codedance.iotp.common.util.JarTool;
import top.codedance.iotp.common.util.SystemUtil;
import org.apache.log4j.Logger;
import org.ini4j.Ini;
import org.ini4j.Wini;

import java.io.File;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class ConnectionPool {
    private static Logger logger = ClientApplication.getLogger(ConnectionPool.class);
    private final int RE_CONNECT_COUNT = 1; //重连次数

    private List<Connection> cs = new ArrayList<>();
    private int size;
    private int initCount;
    private Wini ini = null;

    public ConnectionPool(int size, int initCount, Wini ini) {
        this.size = size;
        this.initCount = initCount;
        this.ini = ini;
    }

    private void createConnect(Integer clientId) throws Exception {
        if (ini != null && ini.containsKey("genericdb")) {
            Ini.Section section = ini.get("genericdb");
            String driveFile, driverClassName, jdbcUrl, user, password;
            if (section.containsKey("poolSize." + clientId)) {
                size = Integer.valueOf(section.get("poolSize." + clientId));
            }
            if (section.containsKey("initPoolSize." + clientId)) {
                initCount = Integer.valueOf(section.get("initPoolSize." + clientId));
            }
            if (section.containsKey("driveFile." + clientId)) {
                driveFile = section.get("driveFile." + clientId);
            } else {
                throw new SQLException("parameter driveFile is empty.");
            }
            if (section.containsKey("driverClassName." + clientId)) {
                driverClassName = section.get("driverClassName." + clientId);
            } else {
                throw new SQLException("parameter driverClassName is empty.");
            }
            if (section.containsKey("jdbcUrl." + clientId)) {
                jdbcUrl = section.get("jdbcUrl." + clientId);
            } else {
                throw new SQLException("parameter jdbcUrl is empty.");
            }
            if (section.containsKey("user." + clientId)) {
                user = section.get("user." + clientId);
            } else {
                throw new SQLException("parameter user is empty.");
            }
            if (section.containsKey("password." + clientId)) {
                password = section.get("password." + clientId);
            } else {
                throw new SQLException("parameter password is empty.");
            }
            String jarFilePath = SystemUtil.getRuntimeDirPath(ClientApplication.class) + driveFile;
            File jarFile = new File(jarFilePath);
            JarTool.loadJar(jarFile.getAbsolutePath());
            Class<?> driverClass = Class.forName(driverClassName);
            DriverManager.registerDriver((Driver)driverClass.newInstance());
            Connection c = DriverManager.getConnection(jdbcUrl, user, password);
            logger.debug("Connecting " + cs.size() + " connection.");
            cs.add(c);
        } else {
            logger.info("database parameters is empty.");
            throw new Exception();
        }
    }

    public synchronized Connection getConnection(Integer clientId) throws InterruptedException {
        Connection c = null;
        int number = 1;
        while (true) {
            while (cs.isEmpty()) {
                if (this.initCount < this.size) {
                    try {
                        createConnect(clientId);
                    } catch (Exception e) {
                        logger.debug(e.getMessage());
                        logger.debug("第" + number + "次，请求失败...");
                        number += 1;
                        if (number > RE_CONNECT_COUNT) {
                            break;
                        }
                        try {
                            Thread.sleep(2000);
                        } catch (Exception ex) {
                        }
                    }
                } else {
                    this.wait();
                }
            }
            if (number > RE_CONNECT_COUNT) {
                logger.debug("请求失败，退出");
                break;
            }
            if (cs.isEmpty()) continue;

            c = cs.remove(0);
            try {
                Statement statement = c.createStatement();
                statement.execute("SELECT 'AA'");
                statement.close();
                break;
            } catch (SQLException ex) {
                logger.debug(ex.getMessage());
                logger.debug("Connection is timeout, reconnecting...");
            }
        }
        return c;
    }

    public synchronized void returnConnection(Connection c) {
        try {
            Statement statement = c.createStatement();
            statement.execute("SELECT 'AA'");
            statement.close();
            //使用完给回连接池中
            cs.add(c);
            //唤醒wait告诉它有新的连接池可用
            this.notifyAll();
        } catch (SQLException ex) {
            logger.debug(ex.getMessage());
        }
    }
}
